package com.ibm.cps.message;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import com.ibm.interfaces.ITimeSeriesSchema;
import com.ibm.util.DataTypes;
import com.ibm.util.ErrorCode;
import com.ibm.util.exception.CPSException;


public class ParsedDataMessageBuilder {
	HashMap<String, Object> buffer;
	ITimeSeriesSchema schema;
	Comparable tskey;
	Long timestamp;
	
	private static Logger logger = Logger.getLogger(ParsedDataMessageBuilder.class);;
	
	
	private ParsedDataMessageBuilder(ITimeSeriesSchema schema,Comparable tskey, Long timestamp) {
		buffer = new HashMap<>();
		this.schema = schema;
		this.tskey = tskey;
		this.timestamp = timestamp;
	};
	
	public static ParsedDataMessageBuilder createBasicBuilder(ITimeSeriesSchema schema,Comparable tskey, Long timestamp){
		ParsedDataMessageBuilder builder = new ParsedDataMessageBuilder(schema, tskey, timestamp);
		return builder;
	}
	
	public static ParsedDataMessageBuilder createInhertiveBuilder(ITimeSeriesSchema outputschema,ParsedDataMessage message,ITimeSeriesSchema parentschema) throws CPSException{
		ParsedDataMessageBuilder builder = new ParsedDataMessageBuilder(outputschema, message.getTsKey(), message.getTimestamp());
		String[] tagNames = parentschema.getTagNames();
		for (int i = 0; i < tagNames.length; i++) {
			String name = tagNames[i];
			byte typeByte = parentschema.getDataType(i);
			Object value = null;
			if(typeByte == DataTypes.DT_DOUBLE_ARRAY || typeByte == DataTypes.DT_INT_ARRAY || typeByte == DataTypes.DT_STRING_ARRAY){
//				value = message.getArrayValue(i);
				Double[] tmp = message.getArray(i);
				builder.append(name, tmp);
			}else{
				value = message.getValue(i);
				builder.append(name, value);
			}
			
		}
		return builder;
	}
	
	
	
	public ParsedDataMessageBuilder append(String fieldName,Object value) throws CPSException{
		if (schema.getTagId(fieldName) == -1) {
			logger.error("not exist this field: " + fieldName);
			throw new CPSException(ErrorCode.NULL_FIELD_ERROR, "not exist this field: " + fieldName);
		}

		buffer.put(fieldName, value);
		return this;
	}
	
	public ParsedDataMessageBuilder CopyValue(ITimeSeriesSchema parentSchema,ParsedDataMessage message) throws CPSException{
		for (int i = 0; i < parentSchema.getTagCount(); i++) {
			String fieldName = parentSchema.getTagNames()[i];
			if(i == parentSchema.getTimestampIndex() || i == parentSchema.getKeyIndex())
				continue;;
			byte type = parentSchema.getDataTypes()[i];
			Object value = null;
			if (DataTypes.isArray(type)) {
				value = message.getArrayValue(i);
			}else {
				value = message.getValue(i);
			}
			this.append(fieldName, value);
		}
		return this;
	}
	
	public ParsedDataMessage toParsedDataMessage() throws CPSException{
		/*if (buffer.size() != schema.getTagCount()) {
			logger.error("You may append not the exact number of schema's value tags' length");
			throw new CPSException(ErrorCode.PARSE_ERROR_CODE, 
					"You may append not the exact number of schema's value tags' length");
		}*/
		ParsedDataMessage message = new ParsedDataMessage(schema.getTagCount(),tskey,timestamp);
		message.setTimestamp(timestamp);
		message.setValue(schema.getTimestampIndex(), timestamp);
		message.setTsKey(tskey);
		message.setValue(schema.getKeyIndex(), tskey);
		
		/* yaoliang: add support for value missing (null as default) */
		/*schema sample {b=2, t=1, k=0}*/
		Iterator<Entry<String, Object>> iter = buffer.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<java.lang.String, java.lang.Object> entry = (Map.Entry<java.lang.String, java.lang.Object>) iter
					.next();
			String tagName = entry.getKey();
			int index = schema.getTagNumber(tagName);
			
			if (index == -1) {
				logger.error("you may input a field["+tagName+"] not exist in schema");
				throw new CPSException(ErrorCode.NULL_FIELD_ERROR, "you may input a field["+tagName+"] not exist in schema");
			}
			
			message.setValue(index, entry.getValue());
		}
		buffer.clear();
		return message;
	}
	
	public boolean validateDataType(Object value,int index){
		boolean valid = true;
//		try {
//			switch(schema.getDataTypes()[index]){
//			case DataTypes.DT_BOOLEAN:
//				return value instanceof Boolean;
//			case DataTypes.DT_DOUBLE:
//				return value instanceof Double;
//			case DataTypes.DT_DOUBLE_ARRAY:
//				if (!value.getClass().isArray()){
//					return false;
//				}
//			case DataTypes.DT_BOOLEAN:
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		return valid;
	}
	
}
